//
//  SimulationParameters.cpp
//  Simulation
//
//  Created by Christopher Kemsley on 3/4/12.
//  Copyright (c) 2012 iAppolopolis. All rights reserved.
//

#include "SimulationParameters.hpp"

#include "Codec.hpp"

#include <stdlib.h>
#include <time.h>
#include <cmath>



#define	symbolToString(symb)	#symb
#define	logVar(var)	Log::notice("SimulationParameters") << "	" << symbolToString(var) << " = " << var ;



using namespace Sim ;



SimulationParameters const&	SimulationParameters :: shared ()
	{
	return _shared() ;
	}


void	SimulationParameters :: loadConfiguration	( Sim::URL const & inURL )
	{
	URL url ( inURL ) ;
	Codec::decode<URL,Settings> ( url , _shared() ) ;
	}

SimulationParameters&	SimulationParameters :: _shared()
	{
	static SimulationParameters s ;
	return s ;
	}

SimulationParameters :: SimulationParameters ()
:	Sim::Settings	( "Simulation" )
,	dataPacketSize	( 1500 )
,	controlPacketSize(30)
,	slotDuration(0,20,0)
,	SIFSDuration(0,20,0)
,	DIFSDuration(0,40,0)
,	transmissionRate(750000)
,	CW0(8)
,	CWMax(1024)
,	lambda(50)
	{
	srand ( time(0) ) ;
	
	add ( "dataPacketSize" , dataPacketSize ) ;
	add ( "controlPacketSize" , controlPacketSize ) ;
	
	add ( "slotDuration" , slotDuration ) ;
	add ( "SIFSDuration" , SIFSDuration ) ;
	add ( "DIFSDuration" , DIFSDuration ) ;
	
	add ( "transmissionRate" , transmissionRate ) ;
	
	add ( "CW0" , CW0 ) ;
	add ( "CWMax" , CWMax ) ;
	add ( "lambda" , lambda ) ;
	}

void SimulationParameters :: validate ()
	{
	if ( dataPacketSize == 0 )
		ThrowException ( "SimulationParameters" , "dataPacketSize is 0" , __FILE__,__LINE__ ) ;
	if ( controlPacketSize == 0 )
		ThrowException ( "SimulationParameters" , "controlPacketSize is 0" , __FILE__,__LINE__ ) ;
	
	if ( slotDuration == Interval::zeroTime )
		ThrowException ( "SimulationParameters" , "slotDuration is 0" , __FILE__,__LINE__ ) ;
	if ( SIFSDuration == Interval::zeroTime )
		ThrowException ( "SimulationParameters" , "SIFSDuration is 0" , __FILE__,__LINE__ ) ;
	if ( DIFSDuration == Interval::zeroTime )
		ThrowException ( "SimulationParameters" , "DIFSDuration is 0" , __FILE__,__LINE__ ) ;
	
	if ( transmissionRate == 0 )
		ThrowException ( "SimulationParameters" , "transmissionRate is 0" , __FILE__,__LINE__ ) ;
	
	if ( CW0 == 0 )
		ThrowException ( "SimulationParameters" , "CW0 is 0" , __FILE__,__LINE__ ) ;
	
	if ( CWMax == 0 )
		ThrowException ( "SimulationParameters" , "CWMax is 0" , __FILE__,__LINE__ ) ;
	
	if ( lambda == 0 )
		ThrowException ( "SimulationParameters" , "lambda is 0" , __FILE__,__LINE__ ) ;
	
	Log::notice("SimulationParameters") << "Simulation Parameters:" ;
	logVar ( dataPacketSize ) ;
	logVar ( controlPacketSize ) ;
	
	logVar ( slotDuration ) ;
	logVar ( SIFSDuration ) ;
	logVar ( DIFSDuration ) ;
	
	logVar ( transmissionRate ) ;
	
	logVar ( CW0 ) ;
	logVar ( CWMax ) ;
	logVar ( lambda ) ;
	}


Sim::Interval const	SimulationParameters :: randomBackoff		( unsigned lambdaScalar ) const
	{
	// Note: (1-U) is the same as (U) if:
	// (1) U is uniformly distributed (which it is)
	// (2) U isn't used except in (1-U) (which it isn't)
	// So: We'll just use U
	double		U	=	rand() % 1000000 ;
	U				/=	1000000. ;
	
	double		v	=	log ( U ) ;
	
	// We're going to generate a micro-seconds value, so we'll divide into 1,000,000
	
	unsigned long	us	=	-((double)(1000000/lambda)) * v ;
	
	Sim::Interval i ( 0 , us , 0 ) ;
	
	if ( i.isNegative() )
		ThrowException ( "SimulationParameters::randomBackoff" , "Calculated yielded a negative random backoff" , __FILE__,__LINE__ ) ;
	
	return i ;
	}
Sim::Interval const	SimulationParameters :: activityDuration	( unsigned long payloadLength ) const
	{
	long	seconds			=	payloadLength / transmissionRate ;
	
	payloadLength	-=	seconds*transmissionRate ;
	payloadLength	*=	1000000 ;
	
	long	microseconds	=	payloadLength / transmissionRate ;
	
	payloadLength	-=	microseconds*transmissionRate ;
	payloadLength	*=	1000000 ;
	
	long	picoseconds		=	payloadLength / transmissionRate ;
	
	return Interval ( seconds , microseconds , picoseconds ) ;
	}